package br.edu.unifei.mestrado.commons.mn;

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import br.edu.unifei.mestrado.commons.graph.GraphWrapper;
import br.edu.unifei.mestrado.commons.graph.NodeWrapper;
import br.edu.unifei.mestrado.commons.partition.AbstractPartition;

public class GN {

	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	private class GraphAndPartition {
		public GraphWrapper graph;
		public AbstractPartition partition;
	}

	private Map<Integer, GraphAndPartition> gn = new HashMap<Integer, GraphAndPartition>();

	public void setGraph(GraphWrapper graph, AbstractPartition partition, int level) {
		GraphAndPartition value = new GraphAndPartition();
		value.graph = graph;
		value.partition = partition;
		gn.put(level, value);
	}

	public GraphWrapper getGraph(int level) {
		if (!gn.containsKey(level)) {
			throw new RuntimeException("O nivel " + level + " não possui grafo.");
		}
		return gn.get(level).graph;
	}

	/**
	 * Repassa o particionamento para o grafo mais fino.
	 * 
	 * @param grafoM_1
	 * @param grafoM
	 */
	public void projectPartitionBack(GraphWrapper grafoM_1, GraphWrapper grafoM) {
		long delta = System.currentTimeMillis();

		grafoM_1.beginTransaction();
		try {
			for (NodeWrapper vertice : grafoM_1.getAllNodes()) {

				// UTIL: repassa o particionamento para o grafo mais fino
				if (vertice.hasInsideOf()) {
					long insideOf = vertice.getInsideOf();
					NodeWrapper coarsed = grafoM.getNode(insideOf);
					vertice.setPartition(coarsed.getPartition());
				} else {

					// copia a partição vertice do grafo mais contraido para o mais fino
					NodeWrapper v = grafoM.getNode(vertice.getId());
					vertice.setPartition(v.getPartition());
				}
			}
			grafoM_1.endTransaction();
		} catch (Exception e) {
			logger.error("Erro repassando particionamento do grafo {} para {}", grafoM_1.getLevel(), grafoM
					.getLevel());
		} finally {
			grafoM_1.finish();
		}

		delta = System.currentTimeMillis() - delta;
		logger.warn("Tempo gasto para repassar o particionamento do grafo {} para {}:" + delta + " ms",
				grafoM_1.getLevel(), grafoM.getLevel());
	}

	public AbstractPartition getPartitionOfLevel(int level) {
		if (!gn.containsKey(level)) {
			throw new RuntimeException("O nivel " + level + " não possui grafo.");
		}
		return gn.get(level).partition;
	}
}
